%{
#include <iostream>
#include <fstream>
using namespace std;
fstream fa3;
int yylex(void);
void yyerror(const char *s);
%}

%union {
    char op;
    int num;
}
%token  NUM ADDOP MULOP LPAREN RPAREN LBRACE RBRACE LBRACKET RBRACKET INT VOID COMMA ASSIGN RET ID SEMICOLON IF ELSE WHILE RETURN SCANF PRINTF

// Grammar:
%start Begin

%%

Begin
: CompUnit  { cout<<"SUCCESS"<<endl; }

CompUnit
: CompUnit GlobalDecl
| GlobalDecl

GlobalDecl
: VarDecl
| FuncDef

VarDecl
: DefType VarDefList SEMICOLON

DefType
: INT
| VOID

VarDefList
: VarDefList COMMA VarDef
| VarDef

VarDef
: ID ArrayExpList
| ID ArrayExpList ASSIGN InitVal

ArrayExpList
: ArrayExpList LBRACKET Expr RBRACKET
| %empty

InitVal
: Expr
| LBRACE ExpList RBRACE

ExpList
: ExpList COMMA Expr
| Expr
| %empty

FuncDef
: DefType ID LPAREN RPAREN Block

Block
: LBRACE BlockItemList RBRACE

BlockItemList
: BlockItemList BlockItem
| %empty

BlockItem
: VarDecl
| Stmt

Stmt
: IfStatement
| WhileStatement
| LBRACE BlockItemList RBRACE
| FuncCallStatement
| AssignmentStatement
| ReturnStatement
| ReadStatement
| WriteStatement

IfStatement
: IF LPAREN Expr RPAREN
| Stmt ELSE Stmt

WhileStatement
: WHILE LPAREN Expr RPAREN Stmt

FuncCallStatement
: FuncCall SEMICOLON

AssignmentStatement
: ID ASSIGN Expr SEMICOLON

ReturnStatement
: RETURN Expr SEMICOLON
| RETURN LPAREN Expr RPAREN SEMICOLON

ReadStatement
: SCANF LPAREN ID RPAREN SEMICOLON

WriteStatement
: PRINTF LPAREN RPAREN SEMICOLON
| PRINTF LPAREN Expr RPAREN SEMICOLON

Expr
: ADDOP Term
| Term
| Expr ADDOP Term

Term
: Factor
| Term MULOP Factor

Factor
: ID
| LPAREN Expr RPAREN
| NUM
| FuncCall

FuncCall
: ID LPAREN RPAREN

%%

void yyerror(const char *s)
{
    fa3.open("fa3.txt", ios::out);
    fa3<<s<<endl;
    fa3.close();
}